﻿#include "FITKAbaAbstractOutput.h"
#include "FITKAbaAbstractStep.h"
#include <QMetaEnum>
#include "FITKAbaStepManager.h"
#include "FITKAbaOutputDefaultVariablesManager.h"


bool Interface::FITKAbaAbstractOutput::isModifiedInStep(int stepId) const
{
    if (m_modifiedDatas.contains(stepId))
        return true;
    return false;
}

void Interface::FITKAbaAbstractOutput::activeStateChanged()
{
    if (m_deactiveStepId == -1)
        return;
    //访问当前算例的分析步管理器，获取分析步顺序id列表。
    QVector<int> stepIds = this->getStepIds();
    int index = stepIds.indexOf(m_deactiveStepId);
    if (index == -1)
        return;
    for (int i = index ; i < stepIds.count(); ++i)
    {
        int id = stepIds[i];
        if (m_modifiedDatas.contains(id))
            m_modifiedDatas.remove(id);
    }
}

bool Interface::FITKAbaAbstractOutput::hasGetStepManager()
{
    if (m_stepManager == nullptr)
        m_stepManager = this->getStepManager(this);
    if (m_stepManager == nullptr)
        return false;
    return true;
}

bool Interface::FITKAbaAbstractOutput::isValidInStep(int stepId /* = 0 */)
{
    if (!this->hasGetStepManager())
        return false;
    FITKAbaAbstractStep* step = m_stepManager->getDataByID(stepId);
    FITKAbaAbstractStep* createdStep = m_stepManager->getDataByID(m_createdStepId);
    if (createdStep->isPerturbation() != step->isPerturbation())
        return false;
    return true;
}

bool Interface::FITKAbaAbstractOutput::copy(FITKAbstractDataObject *obj)
{
    FITKAbaAbstractOutput* output = dynamic_cast<FITKAbaAbstractOutput*>(obj);
    if (output == nullptr)
        return false;
    this->m_createdStepId = output->m_createdStepId;
    this->m_deactiveStepId = output->m_deactiveStepId;
    this->m_stepManager = output->m_stepManager;
    this->setDataObjectName(output->getDataObjectName());
    this->m_data = output->m_data;
    this->m_modifiedDatas = output->m_modifiedDatas;
    this->m_domain = output->m_domain;
    this->m_outputForRebar = output->m_outputForRebar;
    this->m_outputAtSecPts = output->m_outputAtSecPts;
    this->m_specify = output->m_specify;
    return true;
}

Interface::FITKAbaOutputVariable::OutputDomain Interface::FITKAbaAbstractOutput::getDomain() const
{
    return m_domain;
}

void Interface::FITKAbaAbstractOutput::setDomain(FITKAbaOutputVariable::OutputDomain domain)
{
    m_domain = domain;
    //当输出作用的区域发生变化时，对变量列表进行调整
    this->modifySelectedVariables(m_data, m_createdStepId);
    for (auto it = m_modifiedDatas.begin(); it != m_modifiedDatas.end(); it++)
    {
        int stepId = it.key();
        AbaOutputData& data = it.value();
        this->modifySelectedVariables(data, stepId);
    }
}

bool Interface::FITKAbaAbstractOutput::getOutputForRebar() const
{
    return m_outputForRebar;
}

void Interface::FITKAbaAbstractOutput::setOutputForRebar(bool state)
{
    m_outputForRebar = state;
}

Interface::FITKAbaOutputVariable::OutputAtSectionPoints Interface::FITKAbaAbstractOutput::getOutputAtSectionPoints() const
{
    return m_outputAtSecPts;
}

void Interface::FITKAbaAbstractOutput::setOutputAtSectionPoints(FITKAbaOutputVariable::OutputAtSectionPoints value)
{
    m_outputAtSecPts = value;
}

int Interface::FITKAbaAbstractOutput::getSpecify() const
{
    return m_specify;
}

void Interface::FITKAbaAbstractOutput::setSpecify(int value)
{
    m_specify = value;
}

Interface::FITKAbaOutputVariable::OutputFrequency Interface::FITKAbaAbstractOutput::getOutputFrequency(int stepId)
{
    return this->getDataInStep(stepId).getOutputFrequency();
}

void Interface::FITKAbaAbstractOutput::setOutputFrequency(FITKAbaOutputVariable::OutputFrequency value, int stepId)
{
    if (stepId <= 0 || stepId == m_createdStepId)
        m_data.setOutputFrequency(value);
    else
    {
        if (!m_modifiedDatas.contains(stepId))
            m_modifiedDatas[stepId] = this->getDataInStep(stepId);
        m_modifiedDatas[stepId].setOutputFrequency(value);
    }

}

Interface::FITKAbaOutputVariable::OutputTiming Interface::FITKAbaAbstractOutput::getOutputTiming(int stepId)
{
    return this->getDataInStep(stepId).getOutputTiming();
}

void Interface::FITKAbaAbstractOutput::setOutputTiming(FITKAbaOutputVariable::OutputTiming value, int stepId)
{
    if (stepId <= 0 || stepId == m_createdStepId)
        m_data.setOutputTiming(value);
    else
    {
        if (!m_modifiedDatas.contains(stepId))
            m_modifiedDatas[stepId] = this->getDataInStep(stepId);
        m_modifiedDatas[stepId].setOutputTiming(value);
    }
}

Interface::FITKAbaOutputVariable::OutputVariablesSelectMode Interface::FITKAbaAbstractOutput::getSelectMode(int stepId)
{
    return this->getDataInStep(stepId).getSelectMode();
}

void Interface::FITKAbaAbstractOutput::setSelectMode(FITKAbaOutputVariable::OutputVariablesSelectMode mode, int stepId)
{
    if (stepId <= 0 || stepId == m_createdStepId)
    {
        m_data.setSelectMode(mode);
        //根据选择模式，调整变量列表，如选择模式切换为PreselectedDefaults或All时，变量列表做相应变化
        this->modifySelectedVariables(m_data, stepId);
    }
    else
    {
        if (!m_modifiedDatas.contains(stepId))
            m_modifiedDatas[stepId] = this->getDataInStep(stepId);
        AbaOutputData& data = m_modifiedDatas[stepId];
        data.setSelectMode(mode);
        this->modifySelectedVariables(data, stepId);
    }
}

int Interface::FITKAbaAbstractOutput::getEveryNIncrements(int stepId)
{
    return this->getDataInStep(stepId).getEveryNIncrements();
}

void Interface::FITKAbaAbstractOutput::setEvertyNIncrements(int value, int stepId)
{
    if (stepId <= 0 || stepId == m_createdStepId)
        m_data.setEvertyNIncrements(value);
    else
    {
        if (!m_modifiedDatas.contains(stepId))
            m_modifiedDatas[stepId] = this->getDataInStep(stepId);
        m_modifiedDatas[stepId].setEvertyNIncrements(value);
    }
}

int Interface::FITKAbaAbstractOutput::getIntervals(int stepId)
{
    return this->getDataInStep(stepId).getIntervals();
}

void Interface::FITKAbaAbstractOutput::setIntervals(int value, int stepId)
{
    if (stepId <= 0 || stepId == m_createdStepId)
        m_data.setIntervals(value);
    else
    {
        if (!m_modifiedDatas.contains(stepId))
            m_modifiedDatas[stepId] = this->getDataInStep(stepId);
        m_modifiedDatas[stepId].setIntervals(value);
    }
}

double Interface::FITKAbaAbstractOutput::getXUnitsOfTime(int stepId)
{
    return this->getDataInStep(stepId).getXUnitsOfTime();
}

void Interface::FITKAbaAbstractOutput::setXUnitsOfTime(double value, int stepId)
{
    if (stepId <= 0 || stepId == m_createdStepId)
        m_data.setXUnitsOfTime(value);
    else
    {
        if (!m_modifiedDatas.contains(stepId))
            m_modifiedDatas[stepId] = this->getDataInStep(stepId);
        m_modifiedDatas[stepId].setXUnitsOfTime(value);
    }
}

int Interface::FITKAbaAbstractOutput::getTimePointsId(int stepId)
{
    return this->getDataInStep(stepId).getTimePointsId();
}

void Interface::FITKAbaAbstractOutput::setTimePointsId(int id, int stepId)
{
    if (stepId <= 0 || stepId == m_createdStepId)
        m_data.setTimePointsId(id);
    else
    {
        if (!m_modifiedDatas.contains(stepId))
            m_modifiedDatas[stepId] = this->getDataInStep(stepId);
        m_modifiedDatas[stepId].setTimePointsId(id);
    }
}

QList<int> Interface::FITKAbaAbstractOutput::getModeList(int stepId)
{
    return this->getDataInStep(stepId).getModeList();
}

void Interface::FITKAbaAbstractOutput::setModeList(const QList<int> modes, int stepId)
{
    if (stepId <= 0 || stepId == m_createdStepId)
        m_data.setModeList(modes);
    else
    {
        if (!m_modifiedDatas.contains(stepId))
            m_modifiedDatas[stepId] = this->getDataInStep(stepId);
        m_modifiedDatas[stepId].setModeList(modes);
    }
}

int Interface::FITKAbaAbstractOutput::getInteractionId() const
{
    return m_interactionId;
}

void Interface::FITKAbaAbstractOutput::setInteractionId(int id)
{
    m_interactionId = id;
}

QList<QString> Interface::FITKAbaAbstractOutput::getSelectedVariables(int stepId)
{
    return this->getDataInStep(stepId).getSelectedVariables();
}

QList<QString> Interface::FITKAbaAbstractOutput::getSelectedNodalVariables(int stepId)
{
    QList<QString> vars{};
    QMetaEnum m = QMetaEnum::fromType<FITKAbaOutputVariable::OutputVariable>();
    bool ok{false};
    for (const QString& var : this->getDataInStep(stepId).getSelectedVariables())
    {
        int value = m.keyToValue(var.toLatin1().data(), &ok);
        if (ok && value < 1000)
            vars.append(var);
    }
    return vars;
}

QList<QString> Interface::FITKAbaAbstractOutput::getSelectedElementVariables(int stepId)
{
    QList<QString> vars{};
    QMetaEnum m = QMetaEnum::fromType<FITKAbaOutputVariable::OutputVariable>();
    bool ok{false};
    for (const QString& var : this->getDataInStep(stepId).getSelectedVariables())
    {
        int value = m.keyToValue(var.toLatin1().data(), &ok);
        if (ok && (value >=1000 && value < 2000))
            vars.append(var);
    }
    return vars;
}

QList<QString> Interface::FITKAbaAbstractOutput::getSelectedContactVaraiables(int stepId)
{
    QList<QString> vars{};
    QMetaEnum m = QMetaEnum::fromType<FITKAbaOutputVariable::OutputVariable>();
    bool ok{false};
    for (const QString& var : this->getDataInStep(stepId).getSelectedVariables())
    {
        int value = m.keyToValue(var.toLatin1().data(), &ok);
        if (ok && (value >=2000 && value < 3000))
            vars.append(var);
    }
    return vars;
}

QList<QString> Interface::FITKAbaAbstractOutput::getSelectedEnergyVariables(int stepId)
{
    QList<QString> vars{};
    QMetaEnum m = QMetaEnum::fromType<FITKAbaOutputVariable::OutputVariable>();
    bool ok{false};
    for (const QString& var : this->getDataInStep(stepId).getSelectedVariables())
    {
        int value = m.keyToValue(var.toLatin1().data(), &ok);
        if (ok && (value >=3000 && value < 4000))
            vars.append(var);
    }
    return vars;
}

QList<QString> Interface::FITKAbaAbstractOutput::getSelectedIncrementationVariables(int stepId)
{
    QList<QString> vars{};
    QMetaEnum m = QMetaEnum::fromType<FITKAbaOutputVariable::OutputVariable>();
    bool ok{false};
    for (const QString& var : this->getDataInStep(stepId).getSelectedVariables())
    {
        int value = m.keyToValue(var.toLatin1().data(), &ok);
        if (ok && (value >=4000 && value < 5000))
            vars.append(var);
    }
    return vars;
}

void Interface::FITKAbaAbstractOutput::setSelectedVariables(const QList<QString>& vars, int stepId)
{
    if (stepId <= 0 || stepId == m_createdStepId)
        m_data.setSelectedVariables(vars);
    else
    {
        if (!m_modifiedDatas.contains(stepId))
            m_modifiedDatas[stepId] = this->getDataInStep(stepId);
        m_modifiedDatas[stepId].setSelectedVariables(vars);
    }
    this->modifySlectedMode(stepId);
}

void Interface::FITKAbaAbstractOutput::appendVariable(const QString& var, int stepId)
{
    if (stepId <= 0 || stepId == m_createdStepId)
        m_data.appendVariable(var);
    else
    {
        if (!m_modifiedDatas.contains(stepId))
            m_modifiedDatas[stepId] = this->getDataInStep(stepId);
        m_modifiedDatas[stepId].appendVariable(var);
    }
    this->modifySlectedMode(stepId);
}

void Interface::FITKAbaAbstractOutput::removeVariable(const QString& var, int stepId)
{
    if (stepId <= 0 || stepId == m_createdStepId)
        m_data.removeVariable(var);
    else
    {
        if (!m_modifiedDatas.contains(stepId))
            m_modifiedDatas[stepId] = this->getDataInStep(stepId);
        m_modifiedDatas[stepId].removeVariable(var);
    }
    this->modifySlectedMode(stepId);
}

void Interface::FITKAbaAbstractOutput::clearVariables(int stepId)
{
    if (stepId <= 0 || stepId == m_createdStepId)
        m_data.clearVariables();
    else
    {
        if (!m_modifiedDatas.contains(stepId))
            m_modifiedDatas[stepId] = this->getDataInStep(stepId);
        m_modifiedDatas[stepId].clearVariables();
    }
    this->modifySlectedMode(stepId);
}

Interface::AbaOutputData& Interface::FITKAbaAbstractOutput::getDataInStep(int stepId)
{
    if (stepId <= 0)
        return m_data;
    if (m_modifiedDatas.contains(stepId))
        return m_modifiedDatas[stepId];
    QVector<int> stepIds = this->getStepIds();
    int createdStepIndex = stepIds.indexOf(m_createdStepId);
    int stepIndex = stepIds.indexOf(stepId);
    if (!(createdStepIndex >= 0 && createdStepIndex < stepIds.size()))
        return m_data;
    if (!(stepIndex >= 0 && stepIndex < stepIds.size()))
        return m_data;
    for (int i = stepIndex; i >= createdStepIndex; --i)
    {
        int id = stepIds.at(i);
        if (m_modifiedDatas.contains(id))
            return m_modifiedDatas[id];
    }
    return m_data;
}

void Interface::FITKAbaAbstractOutput::modifySelectedVariables(AbaOutputData &data, int stepId)
{
    //当Domain或选择方式发生变化时，自动调整变量列表，
    //变量列表与分析步类型有关
    if (!this->hasGetStepManager())
        return;
    FITKAbaAbstractStep* step = m_stepManager->getDataByID(stepId);
    if (step == nullptr)
        return;
    FITKAbaAbstractStep::FITKAbaStepType type = step->getStepType();
    FITKAbaOutputVariable::OutputVariablesSelectMode mode = data.getSelectMode();
    FITKAbaOutputType outputType = this->getOutputType();
    switch (mode)
    {
    case Interface::FITKAbaOutputVariable::OutputVariablesSelectMode::SelectFromListBelow:
        break;
    case Interface::FITKAbaOutputVariable::OutputVariablesSelectMode::PreselectedDefaults:
        switch (outputType) {
        case FITKAbaOutputType::Field:
            data.setSelectedVariables(FITKAbaOutputDefaultVariablesManager::getInstance()->getPreSelectedDefaultFeildVaraiables(type, m_domain));
            break;
        case FITKAbaOutputType::History:
            data.setSelectedVariables(FITKAbaOutputDefaultVariablesManager::getInstance()->getPreSelectedDefaultHistoryVariables(type, m_domain));
            break;
        default:
            break;
        }
        break;
    case Interface::FITKAbaOutputVariable::OutputVariablesSelectMode::All:
        switch (outputType) {
        case FITKAbaOutputType::Field:
            data.setSelectedVariables(FITKAbaOutputDefaultVariablesManager::getInstance()->getAllDefaultFieldVaraibles(type, m_domain));
            break;
        case FITKAbaOutputType::History:
            data.setSelectedVariables(FITKAbaOutputDefaultVariablesManager::getInstance()->getAllDefaultHistoryVariables(type, m_domain));
            break;
        default:
            break;
        }
        break;
    case Interface::FITKAbaOutputVariable::OutputVariablesSelectMode::EditVariables:
        break;
    default:
        break;
    }
}

void Interface::FITKAbaAbstractOutput::modifySlectedMode(int stepId)
{
    if (!this->hasGetStepManager())
        return;
    FITKAbaAbstractStep* step = m_stepManager->getDataByID(stepId);
    if (step == nullptr)
        return;
    FITKAbaAbstractStep::FITKAbaStepType type = step->getStepType();
    FITKAbaOutputType outputType = this->getOutputType();
    AbaOutputData& data = this->getDataInStep(stepId);
    QStringList vars = data.getSelectedVariables();
    vars.sort();
    QStringList preVars{};
    QStringList allVars{};
    switch (outputType)
    {
    case FITKAbaOutputType::Field:
        preVars = FITKAbaOutputDefaultVariablesManager::getInstance()->getPreSelectedDefaultFeildVaraiables(type, m_domain);
        allVars = FITKAbaOutputDefaultVariablesManager::getInstance()->getAllDefaultFieldVaraibles(type, m_domain);
        break;
    case FITKAbaOutputType::History:
        preVars = FITKAbaOutputDefaultVariablesManager::getInstance()->getPreSelectedDefaultHistoryVariables(type, m_domain);
        allVars = FITKAbaOutputDefaultVariablesManager::getInstance()->getAllDefaultHistoryVariables(type, m_domain);
        break;
    default:
        break;
    }
    preVars.sort();
    allVars.sort();
    if (vars == preVars)
        data.setSelectMode(FITKAbaOutputVariable::OutputVariablesSelectMode::PreselectedDefaults);
    else if (vars == allVars)
        data.setSelectMode(FITKAbaOutputVariable::OutputVariablesSelectMode::All);
    else
        data.setSelectMode(FITKAbaOutputVariable::OutputVariablesSelectMode::SelectFromListBelow);

}

bool Interface::FITKAbaAbstractOutput::getActiveState() const
{
    return m_activeState;
}

void Interface::FITKAbaAbstractOutput::setActiveState(bool stat)
{
    m_activeState = stat;
}
